$type, # MEDIATYPE_xxx (bitmap, drawing, audio...)
$mime, # MIME type, determined by MimeMagic::guessMimeType
$size, # Size in bytes (loadFromXxx)
- $metadata, # Metadata
- $dataLoaded; # Whether or not all this has been loaded from the database (loadFromXxx)
+ $metadata, # Metadata
+ $dataLoaded, # Whether or not all this has been loaded from the database (loadFromXxx)
+ $lastError; # Error string associated with a thumbnail display error
/**#@-*/
* Load metadata from the file itself
*/
function loadFromFile() {
- global $wgUseSharedUploads, $wgSharedUploadDirectory, $wgContLang,
- $wgShowEXIF;
+ global $wgUseSharedUploads, $wgSharedUploadDirectory, $wgContLang, $wgShowEXIF;
$fname = 'Image::loadFromFile';
wfProfileIn( $fname );
$this->imagePath = $this->getFullPath();
$base = $wgUploadBaseUrl;
$path = $wgUploadPath;
}
- $url = "{$base}{$path}" . wfGetHashPath($name, $fromSharedDirectory) . "{$name}";
- return wfUrlencode( $url );
+ $url = "{$base}{$path}" . wfGetHashPath($name, $fromSharedDirectory) . "{$name}";
+ return wfUrlencode( $url );
}
/**
if ($this->canRender()) {
if ( $width > $this->width * $height / $this->height )
- $width = floor( $this->width * $height / $this->height );
- # Note this is the largest width such that the thumbnail's
- # height is at most $height.
-
+ $width = wfFitBoxWidth( $this->width, $this->height, $height );
$thumb = $this->renderThumb( $width );
}
else $thumb= NULL; #not a bitmap or renderable image, don't try.
*/
function renderThumb( $width, $useScript = true ) {
global $wgUseSquid, $wgInternalServer;
- global $wgThumbnailScriptPath, $wgSharedThumbnailScriptPath;
global $wgSVGMaxSize, $wgMaxImageArea, $wgThumbnailEpoch;
$fname = 'Image::renderThumb';
clearstatcache();
}
+ $done = true;
if ( !file_exists( $thumbPath ) ||
filemtime( $thumbPath ) < wfTimestamp( TS_UNIX, $wgThumbnailEpoch ) ) {
$oldThumbPath = wfDeprecatedThumbDir( $thumbName, 'thumb', $this->fromSharedDirectory ).
}
}
if ( !$done ) {
- $this->reallyRenderThumb( $thumbPath, $width, $height );
+ $this->lastError = $this->reallyRenderThumb( $thumbPath, $width, $height );
+ if ( $this->lastError === true ) {
+ $done = true;
+ }
# Purge squid
# This has to be done after the image is updated and present for all machines on NFS,
}
}
- $thumb = new ThumbnailImage( $url, $width, $height, $thumbPath );
+ if ( $done ) {
+ $thumb = new ThumbnailImage( $url, $width, $height, $thumbPath );
+ } else {
+ $thumb = null;
+ }
wfProfileOut( $fname );
return $thumb;
} // END OF function renderThumb
* Really render a thumbnail
* Call this only for images for which canRender() returns true.
*
+ * @param string $thumbPath Path to thumbnail
+ * @param int $width Desired width in pixels
+ * @param int $height Desired height in pixels
+ * @return bool True on error, false or error string on failure.
* @access private
*/
function reallyRenderThumb( $thumbPath, $width, $height ) {
- global $wgSVGConverters, $wgSVGConverter,
- $wgUseImageMagick, $wgImageMagickConvertCommand;
+ global $wgSVGConverters, $wgSVGConverter;
+ global $wgUseImageMagick, $wgImageMagickConvertCommand;
+ global $wgCustomConvertCommand;
$this->load();
+ $err = false;
if( $this->mime === "image/svg" ) {
#Right now we have only SVG
$wgSVGConverters[$wgSVGConverter] );
wfProfileIn( 'rsvg' );
wfDebug( "reallyRenderThumb SVG: $cmd\n" );
- $conv = wfShellExec( $cmd );
+ $err = wfShellExec( $cmd );
wfProfileOut( 'rsvg' );
- } else {
- $conv = false;
}
} elseif ( $wgUseImageMagick ) {
# use ImageMagick
+
+ if ( $this->mime == 'image/jpeg' ) {
+ $quality = "-quality 80"; // 80%
+ } elseif ( $this->mime == 'image/png' ) {
+ $quality = "-quality 95"; // zlib 9, adaptive filtering
+ } else {
+ $quality = ''; // default
+ }
+
# Specify white background color, will be used for transparent images
# in Internet Explorer/Windows instead of default black.
# Note, we specify "-size {$width}" and NOT "-size {$width}x{$height}".
# It seems that ImageMagick has a bug wherein it produces thumbnails of
# the wrong size in the second case.
- $cmd = $wgImageMagickConvertCommand .
- " -quality 85 -background white -size {$width} ".
- wfEscapeShellArg($this->imagePath) . " -resize {$width}x{$height} " .
- wfEscapeShellArg($thumbPath);
+
+ $cmd = wfEscapeShellArg($wgImageMagickConvertCommand) .
+ " {$quality} -background white -size {$width} ".
+ wfEscapeShellArg($this->imagePath) .
+ // For the -resize option a "!" is needed to force exact size,
+ // or ImageMagick may decide your ratio is wrong and slice off
+ // a pixel.
+ " -resize " . wfEscapeShellArg( "{$width}x{$height}!" ) .
+ " -depth 8 " .
+ wfEscapeShellArg($thumbPath) . " 2>&1";
wfDebug("reallyRenderThumb: running ImageMagick: $cmd\n");
wfProfileIn( 'convert' );
- $conv = wfShellExec( $cmd );
+ $err = wfShellExec( $cmd );
+ wfProfileOut( 'convert' );
+ } elseif( $wgCustomConvertCommand ) {
+ # Use a custom convert command
+ # Variables: %s %d %w %h
+ $src = wfEscapeShellArg( $this->imagePath );
+ $dst = wfEscapeShellArg( $thumbPath );
+ $cmd = $wgCustomConvertCommand;
+ $cmd = str_replace( '%s', $src, str_replace( '%d', $dst, $cmd ) ); # Filenames
+ $cmd = str_replace( '%h', $height, str_replace( '%w', $width, $cmd ) ); # Size
+ wfDebug( "reallyRenderThumb: Running custom convert command $cmd\n" );
+ wfProfileIn( 'convert' );
+ $err = wfShellExec( $cmd );
wfProfileOut( 'convert' );
} else {
# Use PHP's builtin GD library functions.
$thumbstat = stat( $thumbPath );
if( $thumbstat['size'] == 0 ) {
unlink( $thumbPath );
+ } else {
+ // All good
+ $err = true;
}
}
+ if ( $err !== true ) {
+ return wfMsg( 'thumbnail_error', $err );
+ } else {
+ return true;
+ }
+ }
+
+ function getLastError() {
+ return $this->lastError;
}
function imageJpegWrapper( $dst_image, $thumbPath ) {
}
function checkDBSchema(&$db) {
+ global $wgCheckDBSchema;
+ if (!$wgCheckDBSchema) {
+ return;
+ }
# img_name must be unique
if ( !$db->indexUnique( 'image', 'img_name' ) && !$db->indexExists('image','PRIMARY') ) {
wfDebugDieBacktrace( 'Database schema not up to date, please run maintenance/archives/patch-image_name_unique.sql' );
* @access public
*/
function wfImageArchiveDir( $fname , $subdir='archive', $shared=false ) {
- global $wgUploadDirectory, $wgHashedUploadDirectory,
- $wgSharedUploadDirectory, $wgHashedSharedUploadDirectory;
+ global $wgUploadDirectory, $wgHashedUploadDirectory;
+ global $wgSharedUploadDirectory, $wgHashedSharedUploadDirectory;
$dir = $shared ? $wgSharedUploadDirectory : $wgUploadDirectory;
$hashdir = $shared ? $wgHashedSharedUploadDirectory : $wgHashedUploadDirectory;
if (!$hashdir) { return $dir.'/'.$subdir; }
}
}
+
+/**
+ * Calculate the largest thumbnail width for a given original file size
+ * such that the thumbnail's height is at most $maxHeight.
+ * @param int $boxWidth
+ * @param int $boxHeight
+ * @param int $maxHeight
+ * @return int
+ */
+function wfFitBoxWidth( $boxWidth, $boxHeight, $maxHeight ) {
+ $idealWidth = $boxWidth * $maxHeight / $boxHeight;
+ $roundedUp = ceil( $idealWidth );
+ if( round( $roundedUp * $boxHeight / $boxWidth ) > $maxHeight )
+ return floor( $idealWidth );
+ else
+ return $roundedUp;
+}
+
?>